package org.amuthu.expression.unary;

import org.amuthu.expression.AbstractExpression;
import org.amuthu.expression.Expression;
import org.amuthu.expression.exception.TypeMismatchException;
import org.amuthu.parser.ExpressionVisitor;

/**
 * Abstract base class for all expressions requiring a single argument.
 */
public class UnaryExpression extends AbstractExpression
{
   private UnaryExprType exprType;

   public UnaryExprType getExprType()
   {
      return exprType;
   }

   /**
    * Create a new unary expression with the given argument.
    *
    * @param	sub	the sub argument
    */
   public UnaryExpression(UnaryExprType exprType, Expression sub)
   {
      super(new Expression[]
              {
                 sub
              });
      this.exprType = exprType;
   }

   /**
    * Return the number of children required in a unary expression.
    * This will always evaluate to <code>1</code>.
    *
    * @return	<code>1</code>
    */
   @Override
   public int getChildCount()
   {
      return 1;
   }

   @Override
   public void accept(ExpressionVisitor visitor)
   {
      visitor.visit(this);
   }

   @Override
   public int checkType() throws TypeMismatchException
   {
      if (exprType == UnaryExprType.NOT)
      {
         if (getChild(0).checkType() == BOOLEAN_TYPE)
         {
            return BOOLEAN_TYPE;
         }
         else
         {
            int type = getChild(0).checkType();
            int expectedType = BOOLEAN_TYPE;
            throw new TypeMismatchException(this, type, expectedType);
         }
      }
      else
      {
         int type = getChild(0).checkType();

         if (type == INTEGER_TYPE || type == FLOAT_TYPE)
         {
            return getType();
         }
         else
         {
            throw new TypeMismatchException(this, type, FLOAT_TYPE);
         }
      }
   }

   @Override
   public int getType()
   {
      if (exprType == UnaryExprType.NOT)
      {
         return BOOLEAN_TYPE;
      }
      else
      {
         return getChild(0).getType();
      }

   }

   @Override
   public String toString()
   {
      String c1 = (getChild(0) != null) ? getChild(0).toString() : "(null)";

      if (exprType == UnaryExprType.NOT)
      {

         return "not(" + c1 + ")";
      }
      else
      {
         return "-(" + c1 + ")";
      }
   }

}
